﻿using System;
using System.Windows.Input;

namespace RiaMVVM
{
	/// I can't take credit for this, I grabbed it off of a blog. As soon as I find said blog, proper credit will be given.
	/// If it was your blog, please let me know.
	public class DelegateCommand : ICommand
	{
		/// <summary>
		/// Occurs when changes occur that affect whether the command should execute.
		/// </summary>
		public event EventHandler CanExecuteChanged;

		Func<object, bool> canExecute;
		Action<object> executeAction;
		bool canExecuteCache;

		/// <summary>
		/// Initializes a new instance of the <see cref="DelegateCommand"/> class.
		/// </summary>
		/// <param name="executeAction">The execute action.</param>
		/// <param name="canExecute">The can execute.</param>
		public DelegateCommand(Action<object> executeAction,
							   Func<object, bool> canExecute)
		{
			this.executeAction = executeAction;
			this.canExecute = canExecute;
		}

		#region ICommand Members
		/// <summary>
		/// Defines the method that determines whether the command 
		/// can execute in its current state.
		/// </summary>
		/// <param name="parameter">
		/// Data used by the command. 
		/// If the command does not require data to be passed,
		/// this object can be set to null.
		/// </param>
		/// <returns>
		/// true if this command can be executed; otherwise, false.
		/// </returns>
		public bool CanExecute(object parameter)
		{
			bool tempCanExecute = canExecute(parameter);

			if (canExecuteCache != tempCanExecute)
			{
				canExecuteCache = tempCanExecute;
				if (CanExecuteChanged != null)
				{
					CanExecuteChanged(this, new EventArgs());
				}
			}

			return canExecuteCache;
		}

		/// <summary>
		/// Defines the method to be called when the command is invoked.
		/// </summary>
		/// <param name="parameter">
		/// Data used by the command. 
		/// If the command does not require data to be passed, 
		/// this object can be set to null.
		/// </param>
		public void Execute(object parameter)
		{
			executeAction(parameter);
		}
		#endregion
	}
}
